#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <errno.h>
#include "raid.h"

/*
 * Libería que permite realizar el manejo de sockets.
 * Nos focalizaremos en los de tipo UNIX, los más utilizados en la aplicación
 *
 */


/*
 * Crea el socket, lo bindea, y lo deja listo para escuchar conexiones entrantes.
 */
int32_t crearConexionConSocket(int32_t puertoFSSyDisco, int32_t* ficheroServer,struct sockaddr_in* server) {

	if ((*ficheroServer = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		printf("No se pudo obtener el fichero descriptor del socket.\n");
		exit(-1);
	}
	printf("Se obtuvo el fichero descriptor correctamente.\n");

	(*server).sin_family = AF_INET;
	(*server).sin_addr.s_addr = INADDR_ANY; /* INADDR_ANY coloca nuestra direccion IP automaticamente */
	(*server).sin_port = htons(puertoFSSyDisco); /* htons transforma el short de maquina a short de red */
	bzero(&((*server).sin_zero), 8); /* Escribimos ceros en el resto de la estructura*/

	if (bind(*ficheroServer, (const struct sockaddr *) &(*server),
			sizeof(struct sockaddr)) == -1) {
		printf("Error al asociar el puerto al socket.\n");
		exit(-1);
	}
	printf("Se asocio bien el puerto al socket.\n");

	if (listen(*ficheroServer, BACKLOG) == -1) {
		printf("No se pudo dejar escuchando al puerto.\n");
		exit(-1);
	}
	return 1;
}


int32_t conectar(char * sIP_remoto, int32_t iPuerto_remoto_para_el_socket) {
	struct sockaddr_in structura_sockaddr;/*estructura para el Connect*/
	char sCadena_para_Log[22] = "\0";
	char error[50] = "\0";
	//unsigned short usPort;
	char sIP[16] = "\0";
   
  int32_t iDescriptor_del_socket; //fichero descriptor
  
  if ((iDescriptor_del_socket=socket(AF_INET, SOCK_STREAM, 0))==-1){
  printf("Socket() error\n");
  exit(-1);
  }
  
	sprintf(sIP, sIP_remoto);
	structura_sockaddr.sin_family = AF_INET;
	structura_sockaddr.sin_addr.s_addr = inet_addr(sIP);
	structura_sockaddr.sin_port = htons(iPuerto_remoto_para_el_socket);
	bzero(&(structura_sockaddr.sin_zero), 8);

	sCadena_para_Log[strlen(sCadena_para_Log)] = '\0';
	strcat(sCadena_para_Log, " : ");

	if (connect(iDescriptor_del_socket, (struct sockaddr *) &structura_sockaddr,
			sizeof(struct sockaddr_in)) == -1)/*conect & check*/
	{
		perror(error);
		return 0;
	}

	return 1;
}

/*
 * Descripcion: Funcion que se encarga de crear el socket y asocia el mismo a una
 *
 */

int32_t prepararSocketUnix(char *NOMBRE_PROCESO) {

	return socket(AF_UNIX, SOCK_STREAM, 0);

}

/** Funcion que se encarga de crear el socket  AF_INET* */

int32_t prepararSocketInet(char * NOMBRE_PROCESO) {
	return socket(AF_INET, SOCK_STREAM, 0);

}

/**Funcion que setea al socket en estado de escucha a la espera de conexiones**/

int32_t escucha(int32_t listener, int32_t CantMaxClientes, char * NOMBRE_PROCESO) {

	if (listen(listener, CantMaxClientes) == -1) {
		return 0;
	}
	return 1;

}

/** Funcion que se encarga del cierre del socket**/
int32_t cerrar(int32_t iDescriptor_del_socket) {
	char sDescriptor_del_socket[16] = "\0";

	close(iDescriptor_del_socket);
	sprintf(sDescriptor_del_socket, "%i cerrado", iDescriptor_del_socket);

	return 1;
}


/**Función para poner a la escucha un socket**/
int32_t escuchaSocketUN(int32_t iDescriptor_del_socket, char * NOMBRE_PROCESO) {
	struct sockaddr_un socket_un_struct;
	int32_t len;

	socket_un_struct.sun_family = AF_UNIX;
	strcpy(socket_un_struct.sun_path, "/root/mysocket");

	unlink(socket_un_struct.sun_path);
	len = strlen(socket_un_struct.sun_path)
			+ sizeof(socket_un_struct.sun_family);

	if (bind(iDescriptor_del_socket, (struct sockaddr *) &socket_un_struct, len)
			== -1) {
		return 0;
	}

	if (listen(iDescriptor_del_socket, 1) == -1) {
		return 0;
	}

	return 1;
}


#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>

int32_t conexionCliente_Aceptar (int32_t descriptor)
{
	socklen_t longitud;
	struct sockaddr Cliente;
	int32_t descriptorDevuelto;


	longitud = sizeof (Cliente);
	descriptorDevuelto = accept (descriptor, &Cliente, &longitud);
	if (descriptorDevuelto == -1)
		return -1;


	return descriptorDevuelto;
}

int32_t socketInet_abrir (int32_t puerto)
{
	struct sockaddr_in Direccion;

	int32_t descriptor;


	descriptor = socket (AF_INET, SOCK_STREAM, 0);
	if (descriptor == -1)
	 	return -1;


	Direccion.sin_family = AF_INET;

	Direccion.sin_port =htons(puerto);
	Direccion.sin_addr.s_addr = inet_addr(stConfig.ipRaid);
	//Direccion.sin_addr.s_addr = inet_addr("192.168.0.11");

	if (bind (descriptor,(struct sockaddr *)&Direccion,sizeof (Direccion)) == -1){
		close (descriptor);
		return -1;
	}


	if (listen (descriptor, 1) == -1)
	{
		close (descriptor);
		return -1;
	}

	return descriptor;
}
int32_t handshake_verificar(char*payload){
	if (payload==NULL)
		return 1;
	else
		return 0;
}
